我們時常會需要處理一些機敏的資料,例如 API Token、資料庫帳號密碼等資訊。在 Pulumi 中,如果我們將這些資訊直接放在 Stack 檔案中,就有可能會洩漏這些敏感資訊。但如果要在執行的時候再由可信任的人去填入這些資料,又會讓自動化的流程不順暢。
這時我們就可以將機敏資訊放置於 Pulumi Secret 中。Pulumi 內建的 Secret 管理機制是由 Pulumi Cloud 代管 Secret key。如果不想要使用 Pulumi Cloud 代管 Secret Key,還可以選擇不同的 Secret Provider。
目前 Pulumi 支援的 Secret Provider 如下:
default
:使用 Pulumi Cloud 管理 Keypassphrase
:在 Local 使用一個密碼保護 Keyawskms
:使用 AWS KMS 管理 keyazurekeyvault
:使用 Azure Key Vault 管理 keygcpkms
:使用 GCP KMS 管理 keyhashivault
:使用 Hashicorp Vault 管理 key如果想要變更 Secret Provider,可以透過 pulumi stack change-secrets-provider
指令變更,使用方式請參考文件。
Note:
change-secrets-provider 指令有一個特殊的用法,就是用來更改 passphrase 的密碼。如果目前的 Secret Provider 已經是 passphrase 了,但想要更改密碼,可以直接執行pulumi stack change-secrets-provider passphrase
指令。輸入舊密碼後,再輸入兩次新密碼即可更改 passphrase 的密碼了。
上一篇文章介紹的如果使用 Config、設定 Config。那如果我們要設定的值是機敏資訊要怎麼做呢?
可以在設定 config 時透過 --secret
參數來達成。
例如以下指令就會設定 dbPassword config,內容為 test123,並會將值加密:
pulumi config set dbPassword test123 --secret
在 Stack 檔案中就能看到,dbPassword 的內容是被加密過的。
config:
aws-vpc-ts:dbPassword:
secure: AAABAP+SKJGIpeiPsE6RJSifIGkm2SCMBVODV0mq5jEytPQcULUu
aws:region: ap-east-1
昨天有提到設定複雜的 config 可以透過直接修改 Stack 檔案達成。但如果複雜的 config 內容是 secret 的話,就還是得透過 CLI 指令來設置。
例如:pulumi config set --path "database.password" test123 --secret
預設狀況下,透過 pulumi config
列出來的 config 列表中,會將 secret 標註為 [secret]
。如果希望可以列出所有資料時,也將 secret 解密顯示的話,可以使用 --show-secrets
參數達成。
例如:
$ pulumi config --show-secrets
KEY VALUE
aws:region ap-east-1
dbPassword test123
接著介紹如何在程式中讀取 Secret 的資料。讀取 Secret 與讀取 Config 的方式大同小異,都是透過 Config 類別來讀取,不同的地方有兩個:
存取 Secret 的方法有:
這些方法其實與讀取 config 的方法相同,差別在於全部都多了 Secret
而已。如果忘記操作方式,可以參考前一篇文章。
以下程式碼即可從 Stack 檔案中將 dbPassword 讀取出來。
const config = new pulumi.Config();
const secret: pulumi.Output<string> | undefined = config.getSecret('dbPassword');
這邊要特別注意的是,程式執行期間,讀取出來的 Secret 資料就會變成明碼,要小心不要將 Secret 透過 log 之類的工具輸出,以免洩漏 Secret。
本次範例繼續延續前面建立 VPC、Subnet 的範例,首先我們需要使用 CLI 將資料庫的帳號密碼設定寫入 Stack 檔案中。
$ pulumi config set --path database.username admin
$ pulumi config set --path database.password test123 --secret
接著就可以開始撰寫 IaC 程式來建立資料庫了。
在程式中,一樣先使用 TypeScript 的 Interface 定義 Database Config。接著使用 requireSecretObject 讀取 Config。雖然我們 config 中混合了一般的 config 與 secret,但在 pulumi 中都可以透過 getSecret / requireSecret 相關的方法讀取。
接著我們就可以建立 SubnetGroup 與 RDS Instance 了。
值得注意的地方在將 databaseConfig 內的 username 與 password 傳遞至 rds.Instance 的方式,是使用到了 lifting 的技巧,讓我們不需要撰寫 username: databaseConfig.apply(db => db.username)
這樣的 Output 轉換程式,就能取得 username Output 值。
// 建立 DatabaseConfig interface 用來代表資料庫設定的 config
interface DatabaseConfig {
username: string;
password: string;
}
// 使用 requireSecretObject 讀取含有 Secret 的 config
const databaseConfig = config.requireSecretObject<DatabaseConfig>("database");
// 在 AWS 中,建立資料庫前需要先有 SubnetGroup,SubnetGroup 中的 Subnet 至少要在 2 個以上的 availability zone,這樣 RDS instance 設定 multiAz 時,才能有另一個可用區可以使用。
const dbSubnet = new aws.rds.SubnetGroup("my-db-subnet", {
subnetIds: Object.values(privateSubnets).map(subnet => subnet.id),
});
// 建立一個 mysql 資料庫,使用 config 中的帳號密碼
const db = new aws.rds.Instance("my-db", {
instanceClass: "db.t3.micro",
allocatedStorage: 20,
engine: "mysql",
username: databaseConfig.username,
password: databaseConfig.password,
dbSubnetGroupName: dbSubnet.name,
skipFinalSnapshot: true,
});
今天的內容比較短一點,本想與昨天的 Config 合併再一起寫,但是又會造成 config 文章太長。我也擔心後面沒有主題寫。明天的文章會介紹 CustomResource
,再來就會進入到一個比較複雜的實戰案例。然後就會進入 Part2,開始寫一些比較進階的議題。
如果讀者對 Pulumi 有任何問題,或是有想了解的內容,也可以在留言許願。畢竟我也還沒想好之後要寫啥。